/**
 * @type {Object} MethodHandler
 * @property {function} handler
 * @property {boolean} returnProxy
 */

/**
 * 
 * @param {Object} options 
 * @param {function} options.defaultHandler
 * @param {Object<string, MethodHandler>} methods
 */
function makeProxy(options) {
    return new Proxy({}, {
        get: (target, prop) => {
            if(target.hasOwnProperty(prop)){
                return target[prop];
            }
            if(!options.methods?.hasOwnProperty(prop) && !options.defaultHandler) {
               throw new Error(`Method ${prop} not found`);
            }
            let handler = null;
            if(options.methods?.hasOwnProperty(prop)) {
                handler = options.methods[prop];
            } else {
                handler = options.defaultHandler;
            }
            return (...args)=>{
                let methodCall = {
                    name: prop,
                    args: args
                }
                if (typeof handler === 'function') {
                    return handler(methodCall);
                } else {
                    if(handler?.returnProxy){
                        handler.handler(methodCall)
                        return makeProxy(options);
                    }
                    return handler.handler(methodCall);
                }
                 
            }
        },
        set: (target, prop, value) => {
            target[prop] = value;
            const methodCall = {
                name: '@propset',
                args:[prop,value]
            }
            if(options.defaultHandler){
                 options.defaultHandler(methodCall);
            }
           
        }
    })
}

module.exports = makeProxy;